﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace TeamsPortal.DataAccess
{
    public class UsersDataAccess : BaseDataAccess
    {
        #region Get by provider
        public User GetByProviderId(AuthenticationProvider provider, string providerId)
        {
            User user = null;

            DbCommand command = GetCommand("SPUsersGetByProvider");
            command.AddParameter<string>(Factory, "Provider", provider.ToString().ToUpper());
            command.AddParameter<string>(Factory, "ProviderId", providerId);

            DataRow dr = GetFirstRow(command);
            if (dr != null)
            {
                user = ParseUserLoginInfo(dr);
            }
            return user;
        }
        #endregion

        #region Get by password reset guid
        public User GetByPasswordResetGuid(AuthenticationProvider provider, string PasswordResetGuid)
        {
            User user = null;

            DbCommand command = GetCommand("SPUsersGetByPasswordResetGuid");
            command.AddParameter<string>(this.Factory, "Provider", provider.ToString().ToUpper());
            command.AddParameter<string>(this.Factory, "PasswordResetGuid", PasswordResetGuid);

            DataRow dr = GetFirstRow(command);
            if (dr != null)
            {
                user = ParseUserLoginInfo(dr);
                user.PasswordResetGuid = dr.GetString("PasswordResetGuid");
                user.PasswordResetGuidExpireDate = dr.GetDate("PasswordResetGuidExpireDate");
            }
            return user;
        }
        #endregion

        public User GetTestUser()
        {
            User user = null;
            DbCommand command = GetCommand("SPUsersGetTestUser");
            DataRow dr = GetFirstRow(command);
            if (dr != null)
            {
                user = ParseUserLoginInfo(dr);
            }
            return user;
        }

        #region Parse user
        protected virtual User ParseUserLoginInfo(DataRow dr)
        {
            var user = new User();
            user.Id = dr.Get<int>("UserId");
            user.UserName = dr.GetString("UserName");
            user.Role = dr.Get<UserRole>("UserGroupId");
            user.Guid = dr.Get<Guid>("UserGuid");
            user.ExternalProfileUrl = dr.GetString("UserExternalProfileUrl");
            user.ProviderLastCall = dr.GetDate("UserProviderLastCall");
            user.Email = dr.GetString("UserEmail");
            decimal offSet = dr.Get<decimal>("UserTimeZone");
            //user.PasswordResetGuid = dr.GetString("PasswordResetGuid");
            //user.PasswordResetGuidExpireDate = dr.GetDate("PasswordResetGuidExpireDate");
            user.TimeZone = new TimeSpan((long)(offSet * (decimal)TimeSpan.TicksPerHour));

            return user;
        }

        protected virtual User ParseUserInfo(DataRow dr)
        {
            var user = new User();
            user.Id = dr.Get<int>("UserId");
            user.UserName = dr.GetString("UserName");
            user.Role = dr.Get<UserRole>("UserGroupId");
            user.RoleName = dr.GetString("UserGroupName");
            user.RegistrationDate = dr.GetDate("UserRegistrationDate");

            decimal offSet = dr.Get<decimal>("UserTimeZone");
            user.TimeZone = new TimeSpan((long)(offSet * (decimal)TimeSpan.TicksPerHour));

            return user;
        }
        #endregion

        #region Add user
        public User AddUser(User user, AuthenticationProvider provider, string providerId)
        {
            DbCommand comm = GetCommand("SPUsersInsertFromProvider");
            comm.AddParameter<string>(Factory, "UserName", user.UserName);
            comm.AddParameter<string>(Factory, "UserProfile", user.Profile);
            comm.AddParameter<string>(Factory, "UserSignature", user.Signature);
            comm.AddParameter<short>(Factory, "UserGroupId", (short)user.Role);
            comm.AddParameter(Factory, "UserBirthDate", DbType.DateTime, user.BirthDate);
            comm.AddParameter<string>(Factory, "UserWebsite", user.Website);
            comm.AddParameter<Guid>(Factory, "UserGuid", Guid.NewGuid());
            comm.AddParameter<decimal>(Factory, "UserTimezone", (decimal)user.TimeZone.TotalHours);
            comm.AddParameter(Factory, "UserEmail", DbType.String, string.IsNullOrWhiteSpace(user.Email) ? null : user.Email);
            comm.AddParameter(Factory, "UserEmailPolicy", DbType.Int32, null);
            comm.AddParameter<string>(Factory, "UserExternalProfileUrl", user.ExternalProfileUrl);
            comm.AddParameter<string>(Factory, "UserProvider", provider.ToString().ToUpper());
            comm.AddParameter<string>(Factory, "UserProviderId", providerId.ToUpper());

            DataRow dr = GetFirstRow(comm);
            user = ParseUserLoginInfo(dr);

            return user;
        }
        #endregion

        #region Edit
        public void Edit(User user)
        {
            DbCommand comm = GetCommand("SPUsersUpdate");
            comm.AddParameter<int>(Factory, "UserId", user.Id);
            comm.AddParameter<string>(Factory, "UserName", user.UserName);
            comm.AddParameter<string>(Factory, "UserProfile", user.Profile);
            comm.AddParameter<string>(Factory, "UserSignature", user.Signature);
            comm.AddParameter(Factory, "UserBirthDate", DbType.DateTime, user.BirthDate);
            comm.AddParameter<string>(Factory, "UserWebsite", user.Website);
            comm.AddParameter<decimal>(Factory, "UserTimezone", (decimal)user.TimeZone.TotalHours);
            comm.AddParameter(Factory, "UserEmail", DbType.String, user.Email);
            comm.AddParameter(Factory, "UserEmailPolicy", DbType.Int32, (int)user.EmailPolicy);
            comm.AddParameter<string>(Factory, "UserExternalProfileUrl", user.ExternalProfileUrl);

            comm.SafeExecuteNonQuery();
        }
        #endregion

        #region Get list
        public List<User> FindByName(string userName)
        {
            DbCommand comm = GetCommand("SPUsersGetByName");
            comm.AddParameter<string>(Factory, "UserName", userName);
            DataTable dt = GetTable(comm);

            var users = new List<User>();
            foreach (DataRow dr in dt.Rows)
            {
                User u = ParseUserInfo(dr);
                users.Add(u);
            }
            return users;
        }

        public List<User> GetAll()
        {
            DbCommand comm = GetCommand("SPUsersGetAll");
            DataTable dt = GetTable(comm);

            var users = new List<User>();
            foreach (DataRow dr in dt.Rows)
            {
                User u = ParseUserInfo(dr);
                u.ProviderId = dr.GetString("UserProviderId");
                users.Add(u);
            }
            return users;
        }
        #endregion

        #region Promote / Demote / Delete
        public void Delete(int id)
        {
            DbCommand comm = GetCommand("SPUsersDelete");
            comm.AddParameter<int>(this.Factory, "UserId", id);

            comm.SafeExecuteNonQuery();
        }

        /// <summary>
        /// Assigns the next (up) user role to the user
        /// </summary>
        /// <param name="id"></param>
        public void Promote(int id)
        {
            DbCommand comm = GetCommand("SPUsersPromote");
            comm.AddParameter<int>(this.Factory, "UserId", id);

            comm.SafeExecuteNonQuery();
        }

        /// <summary>
        /// Assigns the previous (down) user role to the user
        /// </summary>
        /// <param name="id"></param>
        public void Demote(int id)
        {
            DbCommand comm = GetCommand("SPUsersDemote");
            comm.AddParameter<int>(this.Factory, "UserId", id);

            comm.SafeExecuteNonQuery();
        }
        #endregion

        #region Get
        public User Get(int userId)
        {
            User user = null;
            DbCommand comm = GetCommand("SPUsersGet");
            comm.AddParameter<int>(Factory, "UserId", userId);

            DataRow dr = GetFirstRow(comm);
            if (dr != null)
            {
                user = ParseUserInfo(dr);
                user.ExternalProfileUrl = dr.GetString("UserExternalProfileUrl");
                user.Email = dr.GetString("UserEmail");
                user.EmailPolicy = (EmailPolicy)(dr.GetNullable<int?>("UserEmailPolicy") ?? (int)EmailPolicy.None);
                user.AvatarId = dr.GetNullable<int?>("AvatarId");
                user.Website = dr.GetString("UserWebsite");
                user.BirthDate = dr.GetNullable<DateTime?>("UserBirthDate");
            }
            return user;
        }

        public User GetByName(string userName)
        {
            User user = null;
            DbCommand cmd = GetCommand("SPUsersSelectByName");
            cmd.AddParameter<string>(Factory, "UserName", userName);

            DataRow row = GetFirstRow(cmd);
            if (row != null)
            {
                user = ParseUserInfo(row);
                user.AvatarId = row.GetNullable<int?>("AvatarId");
                //user.ExternalProfileUrl = row.GetString("UserExternalProfileUrl");
                //user.Email = row.GetString("UserEmail");
                //user.EmailPolicy = (EmailPolicy)(row.GetNullable<int?>("UserEmailPolicy") ?? (int)EmailPolicy.None);
                //user.Photo = row.GetString("UserPhoto");
                //user.Website = row.GetString("UserWebsite");
                //user.BirthDate = row.GetNullable<DateTime?>("UserBirthDate");
            }

            return user;
        }
        #endregion

        #region Roles
        /// <summary>
        /// Gets the name of the user role
        /// </summary>
        /// <returns></returns>
        public string GetRoleName(UserRole userRole)
        {
            string result = null;
            var comm = GetCommand("SPUsersGroupsGet");
            comm.AddParameter<short>(this.Factory, "UserGroupId", (short)userRole);

            DataRow dr = GetFirstRow(comm);
            if (dr != null)
            {
                result = dr.GetString("UserGroupName");
            }
            return result;
        }

        /// <summary>
        /// Gets a dictionary containing the user roles and its names.
        /// </summary>
        /// <returns></returns>
        public Dictionary<UserRole, string> GetRoles()
        {
            var comm = GetCommand("SPUsersGroupsGetAll");
            var dt = GetTable(comm);
            var roles = new Dictionary<UserRole, string>();
            foreach (DataRow dr in dt.Rows)
            {
                roles.Add(dr.Get<UserRole>("UserGroupId"), dr.GetString("UserGroupName"));
            }
            return roles;
        }
        #endregion

        #region Add email
        public void AddEmail(int id, string email, EmailPolicy policy)
        {
            DbCommand comm = GetCommand("SPUsersUpdateEmail");
            comm.AddParameter<int>(this.Factory, "UserId", id);
            comm.AddParameter<string>(this.Factory, "UserEmail", email);
            comm.AddParameter(this.Factory, "UserEmailPolicy", DbType.Int32, (int)policy);

            comm.SafeExecuteNonQuery();
        }
        #endregion


        #region Update Password Reset Guid
        public void UpdatePasswordResetGuid(int id, string Guid, DateTime expireDate)
        {
            DbCommand comm = GetCommand("SPUsersUpdatePasswordResetGuid");
            comm.AddParameter<int>(Factory, "UserId", id);
            comm.AddParameter<string>(Factory, "PasswordResetGuid", Guid);
            comm.AddParameter(Factory, "PasswordResetGuidExpireDate", DbType.DateTime, expireDate);

            comm.SafeExecuteNonQuery();
        }
        #endregion

        internal void SetAvatar(int userId, int avatarId)
        {
            DbCommand comm = GetCommand("SPUsersUpdateAvatar");
            comm.AddParameter<int>(Factory, "userId", userId);
            comm.AddParameter<int>(Factory, "avatarId", avatarId);

            comm.SafeExecuteNonQuery();
        }
    }
}
